
//package java_cup;

//import java.util.BitArray;


using System.Collections;

/**
 * A set of terminals implemented as a bitset.
 * 
 * @version last updated: 11/25/95
 * @author Scott Hudson
 */
public class VtSet {

    /*-----------------------------------------------------------*/
    /*--- Constructor(s) ----------------------------------------*/
    /*-----------------------------------------------------------*/

    /** Constructor for an empty set. */
    public VtSet() {
        /* allocate the bitset at what is probably the _right Count */
        _elements = new BitArray(Vt.Count);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Constructor for cloning from another set.
     * 
     * @param other the set we are cloning from.
     */
    public VtSet(VtSet other) /*throws internal_error*/ {
        notNull(other);

        _elements = (BitArray)other._elements.Clone();
    }

    /*-----------------------------------------------------------*/
    /*--- (Access to) Static (Class) Variables ------------------*/
    /*-----------------------------------------------------------*/

    /** Constant for the empty set. */
    public static readonly VtSet emptySet = new VtSet();

    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/

    /** Bitset to implement the actual set. */
    public BitArray _elements;

    /*-----------------------------------------------------------*/
    /*--- General Methods ----------------------------------------*/
    /*-----------------------------------------------------------*/

    /**
     * Helper function to test for a null object and throw an exception if one is
     * found.
     * 
     * @param obj the object we are testing.
     */
    public void notNull(Object obj) /*throws internal_error*/ {
        if (obj == null)
            throw new InternalError("Null object used in set operation");
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Determine if the set is empty. */
    public bool empty() {
        return equals(emptySet);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if the set contains a particular terminal.
     * 
     * @param symbolCount the terminal SymbolDraft we are looking for.
     */
    public bool contains(Vt symbol) /*throws internal_error*/ {
        notNull(symbol);
        return _elements.Get(symbol.Index);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Given its index determine if the set contains a particular terminal.
     * 
     * @param indx the index of the terminal in question.
     */
    public bool contains(int indx) {
        return _elements.Get(indx);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if this set is an (improper) subset of another.
     * 
     * @param other the set we are testing against.
     */
    public bool isSubsetOf(VtSet other) /*throws internal_error*/ {
        notNull(other);

        /* make a copy of the other set */
        BitArray copy_other = (BitArray)other._elements.Clone();

        /* and or in */
        copy_other.Or(_elements);

        /* if it hasn't changed, we were a subset */
        return copy_other.Equals(other._elements);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if this set is an (improper) superset of another.
     * 
     * @param other the set we are testing against.
     */
    public bool isSupersetOf(VtSet other) /*throws internal_error*/ {
        notNull(other);
        return other.isSubsetOf(this);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Add a single terminal to the set.
     * 
     * @param symbolCount the terminal being added.
     * @return true if this changes the set.
     */
    public bool Add(Vt symbol) /*throws internal_error*/ {
        bool result;

        notNull(symbol);

        /* see if we already have this */
        result = _elements.Get(symbol.Index);

        /* if not we TryAdd it */
        if (!result)
            _elements.Set(symbol.Index, true);

        return result;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Remove a terminal if it is in the set.
     * 
     * @param symbolCount the terminal being removed.
     */
    public void remove(Vt symbol) /*throws internal_error*/ {
        notNull(symbol);
        _elements.Set(symbol.Index, false);//.clear(symbolCount.index());
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Add (union) in a complete set.
     * 
     * @param other the set being added.
     * @return true if this changes the set.
     */
    public bool AddRange(VtSet other) /*throws internal_error*/ {
        notNull(other);

        /* make a copy */
        BitArray copy = (BitArray)_elements.Clone();

        /* or in the other set */
        _elements.Or(other._elements);

        /* changed if we are not the same as the copy */
        return !_elements.Equals(copy);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if this set intersects another.
     * 
     * @param other the other set in question.
     */
    public bool intersects(VtSet other) /*throws internal_error*/ {
        notNull(other);
        //return _elements.intersects(other._elements);
        return _elements.And(other._elements).HasAnySet();
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Equality comparison. */
    public bool equals(VtSet other) {
        if (other == null)
            return false;
        else
            return _elements.Equals(other._elements);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Generic equality comparison. */
    /*@Override*/
    public override bool Equals(Object? other) {
        if (!(other is VtSet))
            return false;
        else
            return equals((VtSet)other);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /*@Override*/
    public override int GetHashCode() {
        return _elements.GetHashCode();
    }

    /** Convert to string. */
    /*@Override*/
    public override string ToString() {
        String result;
        bool comma_flag;

        result = "{";
        comma_flag = false;
        for (int t = 0; t < Vt.Count; t++) {
            if (_elements.Get(t)) {
                if (comma_flag)
                    result += ", ";
                else
                    comma_flag = true;

                result += Vt.Find(t).Name;
            }
        }
        result += "}";

        return result;
    }

    /*-----------------------------------------------------------*/

}
